<template>
  <ych-modal
    :visible="visible"
    :bodyStyle="bodyStyle"
    :confirmLoading="confirmLoading"
    :fullscreen="true"
    :closable="false"
    :footer="null"
    :destroyOnClose="true"
    @cancel="handleCancel">
    <a-spin :spinning="confirmLoading">
      <div class="bpm-designer-toolbar">
        <span class="bpm-designer-title">{{title}}</span>
        <div class="bpm-designer-button-group">
          <a-popconfirm placement="bottomRight" :title="$t('m.common.tip.save_confirm')" @confirm="() => handleOk()">
            <a-button icon="save" type="primary">{{ $t('m.common.button.save') }}</a-button>
          </a-popconfirm>
          <a-button icon="file-markdown" @click="showDiagramXmlDialog">{{ $t('m.common.button.editSourceFile') }}</a-button>
          <a-button type="link" icon="close" @click="handleCancel"></a-button>
        </div>
      </div>
      <div class="content" ref="content" :style="{height:height}">
        <div class="canvas" ref="canvas"></div>
        <div class="properties-panel-parent" id="js-properties-panel"></div>
      </div>
    </a-spin>
    <user-setting ref="userSetting" @selectFinished="selectUserFinished"/>
    <!--<select-sys-message-template-modal @selectFinished="selectTemplateFinished"
                                       ref="taskReminderTemplate"></select-sys-message-template-modal>-->

    <task-time ref="taskTime" @selectFinished="selectTaskTimeFinished"/>

    <bpm-button-list ref="bpmButtonList" @selectFinished="selectButtonListFinished"/>

    <select-form-tab-dialog ref="selectFormDialog" @selectFinished="selectFormOk" :groupId="groupId"/>

    <select-variable ref="selectVariable" @selectFinished="selectVariableOk"/>

    <form-model-sec-dialog ref="formModelSecDialog" @selectFinished="selectFormModelSecOk"/>

    <ych-icon-dialog ref="iconDialog" @selectFinished="selectIconOk" :iconfont="true"></ych-icon-dialog>

    <select-sub-process-dialog ref="selectSubProcessDialog" @selectFinished="selectSubProcessOK" :groupId="groupId"></select-sub-process-dialog>

    <select-http-view-dialog ref="selectHttpViewDialog" @selectFinished="selectHttpViewOk" :groupId="groupId"/>

    <ych-modal
      :fullscreen="false"
      :title="$t('m.common.button.editSourceFile')"
      :visible="diagramXmlVisible"
      @cancel="handleEditDiagramXmlCancel"
      @ok="handleEditDiagramXmlOk"
      :cancelText="$t('m.common.button.close')">
      <a-textarea v-model="diagram" style="height:100%;"></a-textarea>
    </ych-modal>

    <ych-modal
      :fullscreen="false"
      :visible="scriptValueVisible"
      @cancel="handleScriptValueCancel"
      @ok="handleScriptValueOk"
      :cancelText="$t('m.common.button.close')">
      <ych-code-editor
        v-model="scriptValue"
        language="javascript"
        :fullScreen="false"
        :show-save="true"
        @save="() => $refs.help.save('processScript', scriptValue)"
        :placeholder="$t('m.common.tip.enter_script')"
        :disabled="groovyDisabled"
        style="min-height: 100px; height: 100%;"/>

      <template slot="title">
        <span>{{ $t('m.common.button.editScript') }}</span>
        <ych-help helpCode="processScript" style="padding-left: 8px;"></ych-help>
      </template>
    </ych-modal>

    <!--<template slot="footer">
      <a-button key="back" @click="handleCancel">关闭</a-button>
      <a-button key="editDiagramXml" @click="showDiagramXmlDialog">编辑源文件</a-button>
      <a-button key="submit" type="primary" @click="handleOk">确定</a-button>
    </template>-->

    <ych-help-util ref="help"></ych-help-util>

    <options-value-dialog ref="optionsValueDialog" @ok="handleOptionsValueOk"></options-value-dialog>
  </ych-modal>
</template>

<script>

  import { httpAction, getAction } from '@/api/manage'
  import UserSetting from './bpmDesigner/UserSetting'
  import TaskTime from './bpmDesigner/TaskTime'
  import BpmButtonList from './bpmDesigner/BpmButtonList'
  import SelectFormTabDialog from '../../eform/select/dialog/SelectFormTabDialog'
  import SelectVariable from './bpmDesigner/SelectVariable'
  import FormModelSecDialog from './bpmDesigner/FormModelSecDialog'
  import camundaModdleDescriptor from '@yuncheng/ych-bpm-designer/styles/camunda-bpmn-moddle/resources/camunda'
  import YchConstant from "@/api/YchConstant";
  import {
    utils,
    newModeler
  } from '@yuncheng/ych-bpm-designer'
  import {YchIconDialog, YchCodeEditor} from '@yuncheng/ych-components'
  import SelectSubProcessDialog from '../select/SelectSubProcessDialog'
  import SelectHttpViewDialog from '../../eform/select/dialog/SelectHttpViewDialog'
  import {allowEditScript} from '@/api/manage'
  import YchHelp from '@/components/ych/YchHelp'
  import YchHelpUtil from "../../../components/ych/ych-helps/YchHelpUtil";
  import OptionsValueDialog from './OptionsValueDialog'

  export default {
    name: 'BpmDesignerDialog',
    components: {
      UserSetting,
      TaskTime,
      BpmButtonList,
      SelectFormTabDialog,
      SelectVariable,
      FormModelSecDialog,
      YchIconDialog,
      YchCodeEditor,
      SelectSubProcessDialog,
      SelectHttpViewDialog,
      YchHelp,
      YchHelpUtil,
      OptionsValueDialog,
    },
    props: {
      groupId: {
        type: String,
        required: true
      },
    },
    data () {
      return {
        url: {
          queryById: YchConstant.PREFIX_BPM + '/bpm-back/processDefRest/queryById/v1',
          add: YchConstant.PREFIX_BPM + '/bpm-back/processDefRest/add/v1',
          edit: YchConstant.PREFIX_BPM + '/bpm-back/processDefRest/edit/v1'
        },
        title: this.$t('m.bpm.other.process_design'),
        visible: false,
        bodyStyle: {
          padding: 0,
          margin: 0
        },
        confirmLoading: false,
        processDefId: null,
        design: false,
        type: 'new',
        diagramXmlVisible: false,
        scriptValueVisible: false,
        diagram: null,
        diagramInit: null, // 初始化时的数据
        scriptValue: null,
        // bpmn建模器
        modeler: null,
        container: null,
        canvas: null,
        height: document.body.clientHeight - 50 + 'px',
        groovyDisabled:false,
      }
    },
    methods: {
      add () {
        this.type = 'new'
        this.title =this.$t('m.bpm.other.process_design')
        this.visible = true
        this.processDefId = null
        this.design = true
        this.diagram = null
        if (!this.modeler) {
          this.$nextTick(() => {
            this.init(this.createDiagram)
          })
        } else {
          this.$nextTick(() => {
            this.createDiagram()
          })
        }
      },
      edit (record, design) {
        this.type = 'edit'
        this.title = record.name || this.$t('m.bpm.other.process_design')
        this.visible = true
        this.processDefId = record.id
        this.design = design
        this.diagram = null
        const that = this
        that.confirmLoading = true
        getAction(this.url.queryById, { id: this.processDefId }).then((res) => {
          if (res.success) {
            if (!that.modeler) {
              that.$nextTick(() => {
                that.init(that.openDiagram, res.result)
              })
            } else {
              that.$nextTick(() => {
                that.openDiagram(res.result)
              })
            }
          } else {
            that.error(res.message)
          }
        }).finally(() => {
          that.confirmLoading = false
        })
      },
      handleOk () {
        this.saveDiagram().then(() => {
          if (!this.diagram) {
            this.messageUtil.warning(this.$t('m.common.tip.no_data_modification'))
            return
          }
          const valid = this.validDiagram()
          if (!valid) {
            this.messageUtil.warning(this.$t('m.bpm.verify.tip_blank_required_or_other_error'))
            return
          }
          let httpurl = ''
          let method = ''
          if (!this.processDefId) {
            httpurl += this.url.add + '?type=' + this.type + '&catalogId=' + this.groupId
            method = 'post'
          } else if (this.type == 'newVersion') {
            httpurl += this.url.add + '?type=' + this.type + '&processDefId=' + this.processDefId
            method = 'post'
          } else {
            httpurl += this.url.edit + '?id=' + this.processDefId
            method = 'put'
          }
          const that = this
          that.confirmLoading = true
          httpAction(httpurl, { xml: this.diagram }, method).then((res) => {
            if (res.success) {
              if (res.result == 'ok') {
                that.messageUtil.success(this.$t('m.common.tip.operate_success'))
                that.$emit('ok')
                that.saveDiagramInit();
                that.handleCancel()
              } else {
                that.messageUtil.warning(res.result)
              }
            } else {
              that.messageUtil.warning(res.message)
            }
          }).finally(() => {
            that.confirmLoading = false
          })
        })
      },
      handleCancel() {
        const that = this
        this.saveDiagram().then(() => {
          if (this.diagram === this.diagramInit) {
            this.close();
          } else {
            this.$confirm({
              title: this.$t('m.common.tip.confirm'),
              content: this.$t('m.bpm.design.confirm_close'),
              onOk: function() {
                that.close();
              }
            })
          }
        })
      },
      close() {
        this.visible = false
        this.modeler = null;
      },
      error(message) {
        this.messageUtil.warning(message)
        this.close();
      },
      showUserSettingDialog (json, callback) {
        this.callback = callback
        if (json) {
          json = JSON.parse(json)
        }
        this.$refs.userSetting.open(json)
      },
      selectUserFinished (alias, data) {
        if (data) {
          data = JSON.stringify(data)
        }
        this.callback(alias, data)
      },
      showTimeSettingDialog (callback, title, needVariable, needMultiTimes, oldData) {
        this.callback = callback
        this.$refs.taskTime.title = title
        this.$refs.taskTime.needVariable = needVariable
        this.$refs.taskTime.needMultiTimes = needMultiTimes
        this.$refs.taskTime.initData(oldData)
        this.$refs.taskTime.visible = true
      },
      selectTaskTimeFinished (alias, value) {
        this.callback(alias, value)
      },
      showIconDialog (callback) {
        this.callback = callback
        this.$refs.iconDialog.visible = true
      },
      selectIconOk (value) {
        this.callback(value)
      },
      isDesign () {
        //TODO 暂时不控制
        // return this.design;
        return true
      },
      handleEditDiagramXmlCancel () {
        this.diagramXmlVisible = false
        this.saveDiagram()
      },
      handleEditDiagramXmlOk () {
        this.diagramXmlVisible = false
        this.modeler.importXML(this.diagram)
      },
      showScriptValueDialog (text, callback) {
        this.scriptValue = text || '';
        this.callback = callback
        this.scriptValueVisible = true
      },
      handleScriptValueCancel(){
        this.scriptValueVisible = false
      },
      handleScriptValueOk(){
        this.scriptValueVisible = false
        this.callback(this.scriptValue)
      },
      showOptionsValueDialog(options, callback) {
        this.callback = callback
        this.$refs.optionsValueDialog.open(options)
      },
      handleOptionsValueOk(value) {
        this.callback(value)
      },
      showDiagramXmlDialog () {
        this.saveDiagram().then(() => {
          this.diagramXmlVisible = true
        })
      },
      showButtonListSettingDialog (json, callback, global) {
        this.callback = callback
        if (json) {
          json = JSON.parse(json)
        }
        const userTasks = this.getUserTaskList();
        this.$refs.bpmButtonList.open(json, global, userTasks)
      },
      selectButtonListFinished (alias, data) {
        if (data) {
          data = JSON.stringify(data)
        }
        this.callback(alias, data)
      },
      getUserTaskList() {
        const userTaskList = [];
        if (this.modeler
          && this.modeler._definitions
          && this.modeler._definitions.rootElements
          && this.modeler._definitions.rootElements.length > 0
          && this.modeler._definitions.rootElements[0].flowElements
          && this.modeler._definitions.rootElements[0].flowElements.length > 0)
          this.modeler._definitions.rootElements[0].flowElements.forEach(item => {
            if (item.$type === "bpmn:UserTask") {
              userTaskList.push({
                id: item.id,
                name: item.name || item.id
              });
            }
          })
        return userTaskList;
      },
      showSelectFormDialog (callback) {
        this.callback = callback
        this.$refs.selectFormDialog.radio = true
        this.$refs.selectFormDialog.visible = true
      },
      selectFormOk(selectedRowKeys, selectionRows, type) {
        if (selectionRows) {
          if (type === 'layout') {
            this.callback(selectionRows[0].viewName, selectionRows[0].viewCode, null, null, type)
          } else if (type === 'eform') {
            this.callback(selectionRows[0].formName, selectionRows[0].formCode, null, null, type)
          } else {
            this.callback(selectionRows[0].formName, selectionRows[0].formCode, selectionRows[0].pcUrl, selectionRows[0].mobileUrl, type)
          }
        } else {
          this.callback(null, null, null, null, null)
        }
      },
      showHttpViewDialog(callback) {
        this.callback = callback
        this.$refs.selectHttpViewDialog.radio = true
        this.$refs.selectHttpViewDialog.visible = true
      },
      selectHttpViewOk(selectedRowKeys, selectionRows) {
        const actionType = selectionRows && selectionRows.length > 0 ? 'ok' : 'clear';
        let httpCode, url, method, headers;
        if (actionType === 'ok') {
          httpCode = selectionRows[0].httpCode;
          url = selectionRows[0].httpUrl;
          method = selectionRows[0].httpMethod;
          headers = JSON.parse(selectionRows[0].httpHeaders || "[]")
        }
        this.callback(actionType, httpCode, url, method, headers)
      },
      showSelectVariable (value, variables, formCode, callback) {
        this.callback = callback
        this.$refs.selectVariable.open(value, variables, formCode)
      },
      selectVariableOk (value, variables) {
        this.callback(value, variables)
      },
      showFormModelSecDialog (value, formCode, models, callback, requiredValue, hiddenValue) {
        this.callback = callback
        this.$refs.formModelSecDialog.open(value, formCode, models, requiredValue, hiddenValue)
      },
      selectFormModelSecOk (alias, value, models, requiredAlias, requiredValue, hiddenAlias, hiddenValue) {
        this.callback(alias, value, models, requiredAlias, requiredValue, hiddenAlias, hiddenValue)
      },
      showResourceDialog (callback) {
        this.callback = callback
        this.$refs.selectSubProcessDialog.radio = true;
        this.$refs.selectSubProcessDialog.visible = true;
      },
      selectSubProcessOK(data, selectionRows) {
        this.callback(selectionRows[0].key)
      },
      validDiagram () {
        // const arr_invalid = document.querySelectorAll(".invalid");
        // const arr_error = document.querySelectorAll(".bpp-error-message");
        let count = 0
        /*arr_invalid.forEach((item) => {
          if (!item.classList.contains('bpp-hidden')) {
            count++;
          }
        });
        arr_error.forEach((item) => {
          if (!item.classList.contains('bpp-hidden')) {
            count++;
          }
        });*/
        return count == 0
      },
      createDiagram () {
        const that = this
        const id = utils.nextId('Process_')
        let initialDiagram =
          '<?xml version="1.0" encoding="UTF-8"?>' +
          '<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
          'xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" ' +
          'xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" ' +
          'xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" ' +
          'targetNamespace="http://bpmn.io/schema/bpmn" ' +
          'id="Definitions_1">' +
          '<bpmn:process id="' + id + '" isExecutable="true">' +
          '<bpmn:startEvent id="StartEvent_1"/>' +
          '</bpmn:process>' +
          '<bpmndi:BPMNDiagram id="BPMNDiagram_1">' +
          '<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="' + id + '">' +
          '<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">' +
          '<dc:Bounds height="36.0" width="36.0" x="173.0" y="102.0"/>' +
          '</bpmndi:BPMNShape>' +
          '</bpmndi:BPMNPlane>' +
          '</bpmndi:BPMNDiagram>' +
          '</bpmn:definitions>'
        this.modeler.importXML(initialDiagram, function() {
          that.saveDiagramInit();
        })
      },
      openDiagram (xml) {
        const that = this
        this.modeler.importXML(xml, function (err) {
          if (err) {
            that.error(err.message)
          }
          that.saveDiagramInit();
        })
      },
      saveDiagram () {
        return new Promise((resovle, reject) => {
          const that = this
          this.modeler.saveXML({ format: true }, function (err, xml) {
            that.diagram = xml
            resovle()
          })
        })
      },
      saveDiagramInit () {
        return new Promise((resovle, reject) => {
          const that = this
          this.modeler.saveXML({ format: true }, function (err, xml) {
            that.diagramInit = xml
            resovle()
          })
        })
      },
      init (callback, args) {
        // 获取到属性ref为“content”的dom节点
        this.container = this.$refs.content
        // 获取到属性ref为“canvas”的dom节点
        this.canvas = this.$refs.canvas

        // 建模，官方文档这里讲的很详细
        this.modeler = newModeler(this.canvas, camundaModdleDescriptor)

        callback.apply(this, [args])

        this.saveDiagramInit();
      },
      canEditorGroovy(){
        allowEditScript(true).then(() => {
          this.groovyDisabled = false
        }).catch(()=>{
          this.groovyDisabled = true
        })
      },
    },
    mounted () {
      window.showUserSettingDialog = this.showUserSettingDialog
      window.showTimeSettingDialog = this.showTimeSettingDialog
      window.showButtonListSettingDialog = this.showButtonListSettingDialog
      window.showSelectFormDialog = this.showSelectFormDialog
      window.showSelectVariable = this.showSelectVariable
      window.showFormModelSecDialog = this.showFormModelSecDialog
      window.showIconDialog = this.showIconDialog
      window.showResourceDialog = this.showResourceDialog
      window.showScriptValueDialog = this.showScriptValueDialog
      window.showOptionsValueDialog = this.showOptionsValueDialog
      window.isDesign = this.isDesign
      window.showHttpViewDialog = this.showHttpViewDialog

      this.$nextTick(() => {
        this.canEditorGroovy()
      })
    }
  }
</script>
<style scoped lang="less">
  @import '~@yuncheng/ych-bpm-designer/styles/bpmn-js/assets/diagram-js.css';
  @import '~@yuncheng/ych-bpm-designer/styles/bpmn-js/assets/bpmn-font/css/bpmn-embedded.css';
  /*右边工具栏样式*/
  @import '~@yuncheng/ych-bpm-designer/styles/bpmn-js-properties-panel/assets/bpmn-js-properties-panel.css';
  @import '~@yuncheng/ych-bpm-designer/styles/app.less';

  .bpm-designer-toolbar {
    width: 100%;
    height: 50px;
    line-height: 50px;
    padding: 0px 10px 0px 10px;
    background: #fff;
    border-bottom: 1px solid #e8e8e8;

    .bpm-designer-title {
      height: 50px;
      line-height: 50px;
      font-size: 18px;
      font-weight: 600;
      margin: 0px 0px 0px 10px;
      display: inline-block;
    }

    .bpm-designer-button-group {
      display: inline-block;
      float: right;

      .ant-btn {
        margin: 6px 6px;
      }
    }
  }
</style>
